/** Implementation of Administration class.
 * @file
 * @author Jeremy Schultz
 * Currently used for error handling
 */
#include "Administration.h"

using namespace std;

//-----------------------------------------------------------------------------
// Constructor
Administration::Administration(ostream &_oBuffer)	{
	prevErrorLine = 0;
	errorOccurred = false;
	oBuffer = &_oBuffer;
}

//-----------------------------------------------------------------------------
// Has an error occurred?
bool Administration::ErrorOccurred() {
	return (errorOccurred || prevErrorLine != 0);
}


//-----------------------------------------------------------------------------
// Emit PL assembly code
void Administration::emit(string code) {
	(*oBuffer) << code << endl;
}
//-----------------------------------------------------------------------------
// Emit PL assembly code
void Administration::emit(string code, int arg1) {
	emit(code);
	(*oBuffer) << arg1 << endl;
}
//-----------------------------------------------------------------------------
// Emit PL assembly code
void Administration::emit(string code, int arg1, int arg2) {
	emit(code, arg1);
	(*oBuffer) << arg2 << endl;
}



/*****************************************************************************
 * Parser Errors: Match
 *****************************************************************************/
//-----------------------------------------------------------------------------
// Handle Parser Error (Word)
void Administration::errorMatch(string lex, Token* curToken, int lineNum )	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line "<< lineNum <<" :: ";
		cerr << "Expecting '" << lex << "'";
		butReadA(curToken);
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Numeric)
void Administration::errorMatch(Token* curToken, int lineNum )		{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line "<< lineNum <<" :: ";
		cerr << "Expecting a number ";
		butReadA(curToken);
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Symbol)
void Administration::errorMatch(Token::TokenType type, Token* curToken, int lineNum )	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line "<< lineNum <<" :: ";
		cerr << "Expecting a Symbol '" << Token::toString(type) << "' ";
		butReadA(curToken);
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Helper Function for Parser Error: Match
void Administration::butReadA(Token* t)	{
	cerr << ", but read a ";
	if (t->Type() == Token::ID || t->Type() == Token::KEYWORD)	{
		cerr << "Word, '" << WORD(t)->Lex() << "'" << endl;
	}else if (t->Type() == Token::NUMBER)	{
		cerr << "Number, '" << NUMERIC(t)->Value() << "'" << endl;
	}else	{
		cerr << "Symbol, '" << Token::toString( t->Type() ) << "'" << endl;
	}
}


/*****************************************************************************
 * Parser Errors: 
 *****************************************************************************/
//-----------------------------------------------------------------------------
// Handle Parser Error (Undefined)
void Administration::errorUndefined(string word, int lineNum) {
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Undefined '" << word << "' " << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Invalid Value)
void Administration::errorInvalidValue(int lineNum) {
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected an integer or Boolean" << endl;
	}
	prevErrorLine = lineNum;
}
//-----------------------------------------------------------------------------
// Handle Parser Error (Max Blocks)
void Administration::errorMaxBlocks(int lineNum) {
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Reached Max Blocks, skipping block" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Definition)
void Administration::errorDefinition(int lineNum) {
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected a Definition: constant, variable or procedure" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Variable Definition)
void Administration::errorVariableDef(int lineNum) {
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected a Variable Definition" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Statement)
void Administration::errorStatement(int lineNum) {
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected a Statement: skip, read, write, assignment, " << endl;
		cerr << "procedure call, if or do" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Mismatched Types)
void Administration::errorMismatchedTypes(int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Mismatched Types" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Unbalanced)
void Administration::errorUnbalanced(int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Unbalanced statement" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Not a Procedure)
void Administration::errorNotProcedure(string lex, int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Not defined as a procedure, '" << lex << "'" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Not a Boolean)
void Administration::errorNotBoolean(int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected a Boolean" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Not a Integer)
void Administration::errorNotInteger(int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected an Integer" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Insert)
void Administration::errorInsert(string lex, int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << lex << " is previously defined in the block" << endl;
	}

	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Invalid &, |)
void Administration::errorInvalidPrimOper(int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected operator & or |" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Invalid +, -)
void Administration::errorInvalidAddOper(int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected operator + or -" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Invalid *, /, \)
void Administration::errorInvalidMultiOper(int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected operator *, \\ or /" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Invalid <, =, > )
void Administration::errorInvalidRelatOper(int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected operator <, = or >" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Constant)
void Administration::errorConstant(int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected a integer, Boolean or constant name:  " << endl;
	}
	prevErrorLine = lineNum;
}
//-----------------------------------------------------------------------------
// Handle Parser Error (Factor)
void Administration::errorFactor(int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Expected a Factor: constant, variable, expression" << endl;
	}
	prevErrorLine = lineNum;
}

//-----------------------------------------------------------------------------
// Handle Parser Error (Labels Max)
void Administration::errorLabelMax(int maxLabels, int lineNum)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: ";
		cerr << "Reached max label limit of " << maxLabels << endl;
	}
	prevErrorLine = lineNum;
}











//-----------------------------------------------------------------------------
// Handle Parser Error 
void Administration::error(int lineNum, string errMessage)	{
	if (prevErrorLine != lineNum)	{
		cerr << "Parser error :: Line " << lineNum << " :: " << errMessage << endl;
	}

	prevErrorLine = lineNum;
}





/*****************************************************************************
 * Scanner Errors
 *****************************************************************************/
//-----------------------------------------------------------------------------
// Handle Scanner Error (Definitions)
void Administration::errorInvalidChar(int lineNum, char c)	{
	errorOccurred = true;

	cerr << "Scanner error :: Line " << lineNum << " :: ";
	cerr << "Invalid character '" << c << "', not in the language" << endl;
}
//-----------------------------------------------------------------------------
// Handle Scanner Error (Definitions)
void Administration::errorBadAssign(int lineNum, char c)	{
	errorOccurred = true;

	cerr << "Scanner error :: Line " << lineNum << " :: ";
	cerr << "Invalid character '" << c << "', expecting '='" << endl;
}
//-----------------------------------------------------------------------------
// Handle Scanner Error (Definitions)
void Administration::errorBadNumber(int lineNum, int n, char c)	{
	errorOccurred = true;

	cerr << "Scanner error :: Line " << lineNum << " :: ";
	cerr << "Ill formed number '"<<n<<c<<"', extra character(s) after number" << endl;
}
//-----------------------------------------------------------------------------
// Handle Scanner Error (Definitions)
void Administration::errorEOF(int lineNum)	{
	errorOccurred = true;

	cerr << "Scanner error :: Line " << lineNum << " :: ";
	cerr << "Unexpected End of File" << endl;
}

